// SPDX-License-Identifier: GPL-2.0
/* lombo_framebuffer.c
 *
 * Copyright (C) 2016-2019, LomboTech Co.Ltd.
 * Authors:
 *	lomboswer <lomboswer@lombotech.com>
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 *
 */

#include <drm/drmP.h>
#include <drm/drm_modeset_helper.h>

struct lombo_fb_sc {
	struct drm_framebuffer fb;
	uint32_t color[4];
};

static inline struct lombo_fb_sc *to_lombo_fb_sc(struct drm_framebuffer *fb)
{
	return container_of(fb, struct lombo_fb_sc, fb);
}

static inline struct lombo_fb_sc *to_lombo_fb_sc_check(
	struct drm_framebuffer *fb)
{
	if (fb && (fb->modifier == DRM_FORMAT_MOD_LOMBO_SC))
		return container_of(fb, struct lombo_fb_sc, fb);

	DRM_ERROR("no a lombo sc fb\n");
	return NULL;
}

static void lombo_fb_sc_destroy(struct drm_framebuffer *fb)
{
	struct lombo_fb_sc *fb_sc = to_lombo_fb_sc(fb);

	DRM_DEBUG_KMS("\n");
	drm_framebuffer_cleanup(fb);
	kfree(fb_sc);
}

static int lombo_fb_sc_create_handle(struct drm_framebuffer *fb,
	struct drm_file *file_priv, unsigned int *handle)
{
	DRM_ERROR("no handle for lombo_fb_sc\n");
	return -ENODEV;
}

static const struct drm_framebuffer_funcs lombo_fb_sc_funcs = {
	.destroy = lombo_fb_sc_destroy,
	.create_handle = lombo_fb_sc_create_handle,
};

struct drm_framebuffer *lombo_fb_sc_create(struct drm_device *drm,
	struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd)
{
	const struct drm_format_info *info;
	struct lombo_fb_sc *fb_sc;
	int i, ret;

	info = drm_get_format_info(drm, mode_cmd);
	if (!info)
		return ERR_PTR(-EINVAL);

	fb_sc = kzalloc(sizeof(*fb_sc), GFP_KERNEL);
	if (!fb_sc)
		return ERR_PTR(-ENOMEM);

	drm_helper_mode_fill_fb_struct(drm, &fb_sc->fb, mode_cmd);

	ret = drm_framebuffer_init(drm, &fb_sc->fb, &lombo_fb_sc_funcs);
	if (ret) {
		DRM_ERROR("Failed to init framebuffer: %d\n", ret);
		kfree(fb_sc);
		return ERR_PTR(ret);
	}

	for (i = 0; i < info->num_planes; i++)
		fb_sc->color[i] = mode_cmd->handles[i];

	return &fb_sc->fb;
}

uint32_t lombo_fb_sc_get_color(struct drm_framebuffer *fb, unsigned int plane)
{
	uint32_t color = 0;
	struct lombo_fb_sc *fb_sc = to_lombo_fb_sc_check(fb);

	if (fb_sc && plane < ARRAY_SIZE(fb_sc->color))
		color = fb_sc->color[plane];
	else
		DRM_INFO("fb_sc %s,plane=%d\n", fb_sc ? "ok" : "null", plane);

	return color;
}
